/*=============================================================
* 	Copyright (C) 2024 USTC All rights reserved.
* 	
* 	filename : nn.cpp
* 	Author: Wei Jinsong
* 	Mail: vitus@mainl.ustc.edu.cn
* 	Date 2024-05-19
* 	Abstract 
* 		
*
=============================================================*/

#include "nn.h"
#include "synapse.h"

BaseNetwork::BaseNetwork(sc_module_name name, string file)
    : sc_module(name)
    , clock("clk", 20, SC_NS, 0.5)
{
    SC_TRACEX(clock);

    noc = new BaseNoC("noc", 64, clock);
    cores = new BaseCore*[64];
    synapses = new NeuronSynapse*[64];

    for (int i=0; i<64; i++) {
        cores[i] = new SpikeNeuronCore(("core"+to_string(i)).c_str(), i, clock
                ,file+"/neuron.json", file+"/features_map"+to_string(i)+".json");
        // cores[i]->set_featureMap(file+"/features_map"+to_string(i)+".json");
        synapses[i] = new SpikeNeuronSynapse("core"+to_string(i)+"_synapse", clock
                , file+"/syns/synapse"+to_string(i)+".json");
        cores[i]->synapse.bind(*synapses[i]);
    }

    for (int i=0; i<64; i++) {
        cores[i]->txSpikePort(*noc);
        noc->txSpikePorts[i]->bind(*cores[i]);
    }
}

FSNetwork::FSNetwork(sc_module_name name, string file)
    : sc_module(name)
    , clock("clk", 5, SC_NS, 0.5)
{
    // SC_TRACEX(clock);
    noc = new BaseNoC("noc", 64, clock);
    cores = new BaseCore*[64];
    synapses = new NeuronSynapse*[64];
    // timer = new FSNeuronTimer("fs_timer", 15, 64);

    for (int i=0; i<64; i++) {
        cores[i] = new FSNeuronCore(("core"+to_string(i)).c_str(), i, clock
                ,file+"/neuron"+to_string(i)+".json", file+"/features_map"+to_string(i)+".json");
        // cores[i]->set_featureMap(file+"/features_map"+to_string(i)+".json");

        synapses[i] = new FSNeuronSynapse("core"+to_string(i)+"_synapse", clock
                , file+"/synapse"+to_string(i)+".json");
        cores[i]->synapse.bind(*synapses[i]);
    }

    for (int i=0; i<64; i++) {
        cores[i]->txSpikePort(*noc);
        noc->txSpikePorts[i]->bind(*cores[i]);
        // ((FSNeuronCore*)(cores[i]) )->timer.bind(*timer);
    }
}

void 
FSNetwork::print_spike_sta(ostream& os)
{
    int64_t recv_spike_num = 0;
    int64_t send_spike_num = 0;
    for (int i=0; i<64; i++) {
        cores[i]->print_spike_sta(cout);
        recv_spike_num += cores[i]->get_recv_spike();
        send_spike_num += cores[i]->get_send_spike();
        if (cores[i]->get_recv_spike()!=0 || cores[i]->get_send_spike()!=0) {
            cout << "Core" << i << "'s recv spike num : " << cores[i]->get_recv_spike() << endl;
            cout << "Core" << i << "'s send spike num : " << cores[i]->get_send_spike() << endl;
        }
    }
    cout << "All core's recv spike num : " << recv_spike_num << endl;
    cout << "All core's send spike num : " << send_spike_num << endl;
}


DVSNetwork::DVSNetwork(sc_module_name name, string file)
    : sc_module(name)
    , clock("clk", 5, SC_NS, 0.5)
{
    // SC_TRACEX(clock);
    noc = new BaseNoC("noc", 64, clock);
    cores = new BaseCore*[64];
    synapses = new NeuronSynapse*[64];
    // timer = new FSNeuronTimer("fs_timer", 15, 64);

    for (int i=0; i<64; i++) {
        cores[i] = new AFSNeuronCore(("core"+to_string(i)).c_str(), i, clock
                ,file+"/neuron"+to_string(i)+".json", file+"/features_map"+to_string(i)+".json");

        synapses[i] = new FSNeuronSynapse("core"+to_string(i)+"_synapse", clock
                , file+"/synapse"+to_string(i)+".json");
        cores[i]->synapse.bind(*synapses[i]);
    }

    for (int i=0; i<64; i++) {
        cores[i]->txSpikePort(*noc);
        noc->txSpikePorts[i]->bind(*cores[i]);
        // ((FSNeuronCore*)(cores[i]) )->timer.bind(*timer);
    }
}

void 
DVSNetwork::print_spike_sta(ostream& os)
{
    int64_t recv_spike_num = 0;
    int64_t send_spike_num = 0;
    for (int i=0; i<64; i++) {
        cores[i]->print_spike_sta(cout);
        recv_spike_num += cores[i]->get_recv_spike();
        send_spike_num += cores[i]->get_send_spike();
        if (cores[i]->get_recv_spike()!=0 || cores[i]->get_send_spike()!=0) {
            cout << "Core" << i << "'s recv spike num : " << cores[i]->get_recv_spike() << endl;
            cout << "Core" << i << "'s send spike num : " << cores[i]->get_send_spike() << endl;
        }
    }
    cout << "All core's recv spike num : " << recv_spike_num << endl;
    cout << "All core's send spike num : " << send_spike_num << endl;
}


